package eu.robico.simulator.simulatorinterface;

import java.awt.EventQueue;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Observer;

import eu.robico.simulator.simulatorinterface.SimulatorStatus.ConnectionState;
import eu.robico.simulator.simulatorinterface.communication.Host;
import eu.robico.simulator.simulatorinterface.communication.Protocol.Trigger;
import eu.robico.simulator.simulatorinterface.communication.Protocol.Update;
import eu.robico.simulator.simulatorinterface.communication.Protocol.UpdateType;
import eu.robico.simulator.simulatorinterface.communication.Protocol.WheelStatus;


public class SimulatorInterface 
{
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) 
	{	
		//Create SimulatorInterface
		final SimulatorInterface simulatorInterface = new SimulatorInterface(MainController.getInstance());
		
		//Create GUI
		EventQueue.invokeLater(new Runnable() 
		{
			public void run() 
			{
				try {
					// enable anti-aliased text:
					System.setProperty("awt.useSystemAAFontSettings","lcd");
					System.setProperty("swing.aatext", "true");
					ApplicationWindow window = new ApplicationWindow(MainController.getInstance());
					window.setVisibility(true);
					
					//Add GUI as data-observer
					simulatorInterface.addObserver(window);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
	
	//TODO: do something with this or just remove it
	@SuppressWarnings("unused")
	final private MainController controller;
	private Host host;
	private RobotStatus robotStatus = new RobotStatus();
	private SimulatorStatus simulatorStatus = new SimulatorStatus();
	
	public SimulatorInterface(MainController controller)
	{
		this.controller = controller;
		controller.setSimulatorInterface(this);
	}
	
	public void connect(String ip, short port)
	{
		if (simulatorStatus.isConnected())
		{
			simulatorStatus.setConnectionStatus("Already connected");
			return;
		}
		try {
			robotStatus.reset();
			host = new Host(this, ip, port);
			simulatorStatus.setIp(ip);
			simulatorStatus.setPort(port);
			simulatorStatus.setConnectionState(ConnectionState.CONNECTED);
			simulatorStatus.setConnectionStatus("Connected");
		} catch (UnknownHostException e) {
			simulatorStatus.setConnectionState(ConnectionState.ERROR);
			simulatorStatus.setConnectionStatus("Unknown host");
		} catch (IOException e) {
			simulatorStatus.setConnectionState(ConnectionState.ERROR);
			simulatorStatus.setConnectionStatus("Connection error");
		}
	}
	
	public void sendTrigger(Trigger trigger)
	{
		if (simulatorStatus.isConnected())
		{
			host.sendTrigger(trigger);
		}
	}
	
	public void disconnected()
	{
		simulatorStatus.setConnectionState(ConnectionState.DISCONNECTED);
		simulatorStatus.setConnectionStatus("Disconnected");
		host = null;
	}
	
	public void disconnected(Update<String> update)
	{
		ConnectionState state = (update.getType() == UpdateType.CONNECTION) ? 
				ConnectionState.DISCONNECTED : ConnectionState.ERROR;
		simulatorStatus.setConnectionState(state);
		simulatorStatus.setConnectionStatus(update.getUpdate());
		host = null;
	}
	
	public void disconnect()
	{
		if (!simulatorStatus.isConnected())
		{
			simulatorStatus.setConnectionState(ConnectionState.ERROR);
			simulatorStatus.setConnectionStatus("Not connected");
			return;
		}
		host.close();
	}
	
	public void takeIntegerUpdate(Update<Integer> update) 
	{
		switch (update.getType()) 
		{
		case BUZZER:
			robotStatus.setBuzzer((update.getUpdate() != 0));
			break;
		case COLORLANELEFTSENSOR:
			robotStatus.setColorLaneLeftSensor((update.getUpdate() != 0));
			break;
		case COLORLANERIGHTSENSOR:
			robotStatus.setColorLaneRightSensor((update.getUpdate() != 0));
			break;
		case CROSSROADSSENSOR:
			robotStatus.setCrossRoadsSensor((update.getUpdate() != 0));
			break;
		case LED1:
			robotStatus.setLed1((update.getUpdate() != 0));
			break;
		case LED2:
			robotStatus.setLed2((update.getUpdate() != 0));
			break;
		case LEFTWHEEL:
			robotStatus.setLeftWheelStatus(WheelStatus.valueOf(update.getUpdate()));
			break;
		case RIGHTWHEEL:
			robotStatus.setRightWheelStatus(WheelStatus.valueOf(update.getUpdate()));
			break;
		case SLEEP:
			robotStatus.setSleep((update.getUpdate() != 0));
			break;
		case WHEELCONTROL:
			robotStatus.setWheelControl((update.getUpdate() != 0));
			break;
		case SIDEEXITLEFTSENSOR:
			robotStatus.setLeftSideExitSensor((update.getUpdate() != 0));
			break;
		case SIDEEXITRIGHTSENSOR:
			robotStatus.setRightSideExitSensor((update.getUpdate() != 0));
			break;
		default:
		}
	}
	
	public void takeStringUpdate(Update<String> update)
	{
		switch (update.getType())
		{
		//TODO: fix this
//		case STATUS:
//			simulatorStatus.setSimulatorStatus(update.getUpdate());
//			return;
		default:
		}
	}
	
	public void addObserver(Observer observer)
	{
		robotStatus.addObserver(observer);
		simulatorStatus.addObserver(observer);
	}
	
	public RobotStatus getRobotStatusCopy()
	{
		return RobotStatus.copyOf(robotStatus);
	}
	
	public SimulatorStatus getSimulatorStatusCopy()
	{
		return SimulatorStatus.copyOf(simulatorStatus);
	}
	
}
